/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.javadoc.comments; import java.util.ArrayList; import java.util.Iterator; import java.util.Collection; import java.text.MessageFormat; import javax.swing.DefaultListModel; import java.util.ResourceBundle; import java.lang.reflect.Modifier; import org.openide.src.*; import org.openide.cookies.SourceCookie; import org.openide.cookies.OpenCookie; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.netbeans.modules.java.JavaDataObject; /** Contains static methods for generating default JavaDoc comments for * java data object hierarchy elements. * * Checks for Comment errors in JavaDataObjects * * @author Petr Hrebejk */ public class AutoCommenter extends Object implements JavaTagNames { public static final int JDC_OK = 1; public static final int JDC_MISSING = 2; public static final int JDC_ERROR = 4; private static final ResourceBundle bundle = NbBundle.getBundle( AutoCommenter.class ); ArrayList elements; Node[] nodes; /** Creates an empty AutoCommenter */ AutoCommenter() { this( new Node[0] ); } /** Creates Auto commenter for nodes */ AutoCommenter ( Node[] nodes ) { this.nodes = nodes; //refreshFromSource(); } void refreshFromSource() { elements = new ArrayList(); for (int i = 0; i < nodes.length; i++ ) { SourceCookie sc = (SourceCookie)nodes[i].getCookie( SourceCookie.class ); if ( sc == null ) continue; SourceElement se = sc.getSource(); if ( se != null ) { ClassElement[] ces = se.getAllClasses(); for( int j = 0; j < ces.length; j++ ) addElements( ces[j] ); } //( ClassElement )nodes[i].getCookie( ClassElement.class ); //if ( ce != null ) // addElements( ce ); } } void prepareListModel( DefaultListModel listModel, int mask, boolean pckg, int err_mask ) { Iterator it = elements.iterator(); while( it.hasNext() ) { Element el = (Element)it.next(); if ( acceptElement( el, mask, pckg, err_mask ) ) { listModel.addElement( el ); } } } static boolean acceptElement( Element el, int mask, boolean pckg, int err_mask ) { // Test whether the element is accepted by error mask if ( ( el.getErrorNumber() & err_mask ) == 0 ) return false; // Test whether the element is accepted by access mask if ( ( el.getModifiers() & ( Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE ) ) == 0 ) { if ( !pckg ) return false; } else if ( ( el.getModifiers() & mask ) == 0 ) return false; return true; } DefaultListModel prepareListModel( int mask, boolean pckg, int err_mask ) { DefaultListModel dm = new DefaultListModel(); prepareListModel( dm, mask, pckg, err_mask ); return dm; } private void addElements( ClassElement classElement ) { elements.add( new Element.Class( classElement ) ); FieldElement[] fe = classElement.getFields(); for( int i = 0; i < fe.length; i++ ) { elements.add( new Element.Field ( fe[i] ) ); } ConstructorElement[] ce = classElement.getConstructors(); for( int i = 0; i < ce.length; i++ ) { elements.add( new Element.Constructor ( ce[i] ) ); } MethodElement[] me = classElement.getMethods(); for( int i = 0; i < me.length; i++ ) { elements.add( new Element.Method ( me[i] ) ); } /* getAllClasses is already recursive ClassElement[] ice = classElement.getClasses(); for( int i = 0; i < ice.length; i++ ) { addElements( ice[i] ); } */ } /** innerclass holds the element and the informations about comment errors */ static abstract class Element { protected DefaultListModel errorList; MemberElement srcElement = null; int srcError = JDC_OK; Element( MemberElement srcElement ) { this.srcElement = srcElement; checkError(); } String getName() { return getNameFormat().format( srcElement ); } MemberElement getSrcElement() { return srcElement; } int getModifiers() { return srcElement.getModifiers(); } int getErrorNumber() { return srcError; } void viewSource() { OpenCookie oc = ((OpenCookie)srcElement.getCookie( OpenCookie.class )); oc.open(); } DefaultListModel getErrorList() { return errorList; } /** Returns the source for this particular element. Used for locking purposes. */ SourceElement findSource() { ClassElement decl = srcElement.getDeclaringClass(); if (decl == null && (srcElement instanceof ClassElement)) { decl = (ClassElement)srcElement; } if (decl == null) return null; return decl.getSource(); } abstract String[] getNotPermittedTags(); abstract boolean elementTagsOk(); abstract void autoCorrect() throws SourceException; abstract JavaDoc getJavaDoc(); abstract ElementFormat getNameFormat(); abstract String typeToString(); static boolean isPermittedTag( JavaDocTag tag, String[] notPermittedTags ) { String tagName = tag.name(); for ( int i = 0; i < notPermittedTags.length; i++ ) { if ( tagName.equals( notPermittedTags[i] ) ) return false; } return true; } void modifyJavaDoc(Runnable mutator) throws SourceException { SourceElement src = findSource(); if (src == null) { mutator.run(); } else { src.runAtomicAsUser(mutator); } } private static boolean isEmptyString( String string ) { return string == null || string.length() <= 0; } /** Checks syntax of the tags */ boolean isOkTag( JavaDocTag tag ) { if ( isEmptyString( tag.text() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_EmptyTag" ), new Object[] { tag.name() } ) ); return false; } if ( tag instanceof JavaDocTag.See ) { } else if ( tag instanceof JavaDocTag.Param ) { if ( isEmptyString( ((JavaDocTag.Param)tag).parameterName() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_ParamNoName" ), new Object[] { tag.name() } ) ); return false; } if ( isEmptyString( ((JavaDocTag.Param)tag).parameterComment() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_ParamNoDescr" ), new Object[] { tag.name(), ((JavaDocTag.Param)tag).parameterName() } ) ); return false; } } else if ( tag instanceof JavaDocTag.Throws ) { if ( isEmptyString( ((JavaDocTag.Throws)tag).exceptionName() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_ThrowsNoName" ), new Object[] { tag.name() } ) ); return false; } if ( isEmptyString( ((JavaDocTag.Throws)tag).exceptionComment() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_ThrowsNoDescr" ), new Object[] { tag.name(), ((JavaDocTag.Throws)tag).exceptionName() } ) ); return false; } } else if ( tag instanceof JavaDocTag.SerialField ) { if ( isEmptyString( ((JavaDocTag.SerialField)tag).fieldName() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_SerialFieldNoName" ), new Object[] { tag.name() } ) ); return false; } if ( isEmptyString( ((JavaDocTag.SerialField)tag).fieldType() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_SerialFieldNoType" ), new Object[] { tag.name(), ((JavaDocTag.SerialField)tag).fieldName() } ) ); return false; } if ( isEmptyString( ((JavaDocTag.SerialField)tag).description() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_SerialFieldNoDescr" ), new Object[] { tag.name(), ((JavaDocTag.SerialField)tag).fieldName() } ) ); return false; } } return true; } void checkError() { errorList = new DefaultListModel(); JavaDoc jdoc = getJavaDoc(); if ( jdoc.isEmpty() ) { srcError = JDC_MISSING; errorList.addElement( bundle.getString( "ERR_JavadocMissing" ) ); return; } JavaDocTag[] tags = jdoc.getTags(); boolean error = false; if ( jdoc.getText() == null || jdoc.getText().length() <= 0 ) { errorList.addElement( bundle.getString( "ERR_EmptyText" ) ); error = true; } for ( int i = 0; i < tags.length; i ++ ) { if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_BadTag" ), new Object[] { tags[i].name(), typeToString() } ) ); error = true; continue; } if ( !isOkTag( tags[i] ) ) { error = true; continue; } } if ( !elementTagsOk( ) ) { error = true; } if ( !error ) { errorList.addElement( bundle.getString( "ERR_JavadocOK" ) ); } srcError = error ? JDC_ERROR : JDC_OK; } boolean isCorrectable() { JavaDocTag[] tags = getJavaDoc().getTags(); for ( int i = 0; i < tags.length; i ++ ) { if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) { return true; } } return false; } void autoCorrect( JavaDoc jdoc ) throws SourceException { JavaDocTag[] tags = jdoc.getTags(); ArrayList correctedTags = new ArrayList( tags.length ); String correctedText; correctedText = jdoc.getText(); if ( correctedText == null ) { correctedText = ""; // NOI18N } for ( int i = 0; i < tags.length; i ++ ) { if ( !Element.isPermittedTag( tags[i], getNotPermittedTags() ) ) { continue; } correctedTags.add( tags[i] ); } //jdoc.setRawText( generateRawText( correctedText, (Collection)correctedTags ) ); jdoc.changeTags( (JavaDocTag[])correctedTags.toArray( new JavaDocTag[ correctedTags.size() ] ), JavaDoc.SET ); } static class Class extends Element { private static final String[] NOT_PERMITTED_TAGS = { TAG_EXCEPTION, TAG_PARAM, TAG_RETURN, TAG_SERIAL, TAG_SERIALDATA, TAG_SERIALFIELD, TAG_THROWS, }; private static final ElementFormat nameFormat = new ElementFormat( "{m} {C}" ); // NOI18N Class( ClassElement element ) { super( element ); } String[] getNotPermittedTags() { return NOT_PERMITTED_TAGS; } boolean elementTagsOk() { return true; } void autoCorrect() throws SourceException { super.autoCorrect( getJavaDoc() ); } boolean isCorrectable() { return super.isCorrectable(); } String typeToString() { return ((ClassElement)srcElement).isInterface() ? "interface" : "class"; // NOI18N } JavaDoc getJavaDoc() { return ((ClassElement)srcElement).getJavaDoc(); } ElementFormat getNameFormat () { return nameFormat; } } static class Field extends Element { private static final String[] NOT_PERMITTED_TAGS = { TAG_AUTHOR, TAG_EXCEPTION, TAG_PARAM, TAG_RETURN, TAG_SERIALDATA, TAG_THROWS, TAG_VERSION }; private static final ElementFormat nameFormat = new ElementFormat( "{m} {t} {n}" ); // NOI18N Field( FieldElement element ) { super( element ); } JavaDoc getJavaDoc() { return ((FieldElement)srcElement).getJavaDoc(); } String[] getNotPermittedTags() { return NOT_PERMITTED_TAGS; } String typeToString() { return "field"; // NOI18N } boolean elementTagsOk() { return true; } void autoCorrect() throws SourceException { super.autoCorrect( getJavaDoc() ); } boolean isCorrectable() { return super.isCorrectable(); } ElementFormat getNameFormat () { return nameFormat; } } static class Constructor extends Element { private static final String[] NOT_PERMITTED_TAGS = { TAG_AUTHOR, TAG_SERIAL, TAG_SERIALFIELD, TAG_VERSION, TAG_RETURN }; private static final ElementFormat nameFormat = new ElementFormat( "{m} {n} ( {p} )" ); // NOI18N Constructor( ConstructorElement element ) { super( element ); } JavaDoc getJavaDoc() { return ((ConstructorElement)srcElement).getJavaDoc(); } String[] getNotPermittedTags() { return NOT_PERMITTED_TAGS; } String typeToString() { return "constructor"; // NOI18N } boolean elementTagsOk() { return elementTagsOk( null, false ); } boolean elementTagsOk( ArrayList correctedTags, boolean checkOnly ) { boolean error = false; // Check param tags JavaDocTag.Param[] ptags = ((ConstructorElement)srcElement).getJavaDoc().getParamTags(); boolean[] ptags_ok = new boolean[ ptags.length ]; MethodParameter[] params = ((ConstructorElement)srcElement).getParameters(); boolean[] params_ok = new boolean[ params.length ]; for( int i = 0; i < ptags.length; i++ ) for( int j = 0; j < params.length; j ++ ) if ( ptags[i].parameterName() != null && ptags[i].parameterName().equals( params[j].getName() ) ) { ptags_ok[i] = true; params_ok[j] = true; break; } for( int i = 0; i < ptags.length; i++ ) { if ( !ptags_ok[i] ) { if ( checkOnly ) { return false; } else if ( correctedTags == null ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_NoSuchParam" ), new Object[] { ptags[i].name() } ) ); } error = true; } else if ( correctedTags != null ) { correctedTags.add( ptags[i] ); } } for( int i = 0; i < params.length; i ++ ) { if ( !params_ok[i] ) { if ( checkOnly ) { return false; } else if ( correctedTags == null ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_NoTagForParam" ), new Object[] { params[i].getName() } ) ); } else { correctedTags.add( JavaDocSupport.createParamTag( TAG_PARAM, params[i].getName() ) ); } error = true; } } // Check throws tags JavaDocTag.Throws[] ttags = ((ConstructorElement)srcElement).getJavaDoc().getThrowsTags(); boolean[] ttags_ok = new boolean[ ttags.length ]; Identifier[] excs = ((ConstructorElement)srcElement).getExceptions(); boolean[] excs_ok = new boolean[ excs.length ]; for( int i = 0; i < ttags.length; i++ ) for( int j = 0; j < excs.length; j ++ ) if ( ttags[i].exceptionName() != null ) { Identifier tagExId = Identifier.create(ttags[i].exceptionName() ); if ( tagExId != null && ( tagExId.compareTo( excs[j], false ) || tagExId.getName().equals( excs[j].getName() ) ) ) { ttags_ok[i] = true; excs_ok[j] = true; break; } } for( int i = 0; i < ttags.length; i++ ) { if ( !ttags_ok[i] ) { if ( checkOnly ) { return false; } else if ( correctedTags == null ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_NoSuchException" ), new Object[] { ttags[i].name() } ) ); } error = true; } else if ( correctedTags != null ) { correctedTags.add( ttags[i] ); } } for( int i = 0; i < excs.length; i ++ ) { if ( !excs_ok[i] ) { if ( checkOnly ) { return false; } else if ( correctedTags == null ) { errorList.addElement( MessageFormat.format( bundle.getString( "ERR_NoTagForException" ), new Object[] { excs[i].getName() } ) ); } else { correctedTags.add( JavaDocSupport.createThrowsTag( TAG_THROWS, excs[i].getName() ) ); } error = true; } } return !error; } boolean isCorrectable () { if ( super.isCorrectable() ) return true; return !elementTagsOk( null, true ); } void autoCorrect() throws SourceException { autoCorrect( getJavaDoc() ); } void autoCorrect( JavaDoc jDoc ) throws SourceException { JavaDoc.Method jdTemp = JavaDocSupport.createMethodJavaDoc(getJavaDoc().getRawText()); // create comment without throws and params JavaDocTag tags[] = jdTemp.getTags(); ArrayList stdTags = new ArrayList( tags.length ); for( int i = 0; i < tags.length; i++ ) { if ( !( tags[i] instanceof JavaDocTag.Param ) && !( tags[i] instanceof JavaDocTag.Throws ) ) { stdTags.add( tags[i] ); } } // jdTemp.setRawText( generateRawText( jdTemp.getText(), stdTags ) ); jdTemp.changeTags( (JavaDocTag[])stdTags.toArray( new JavaDocTag[ stdTags.size() ] ), JavaDoc.SET ); super.autoCorrect( jdTemp ); ArrayList correctedTags = new ArrayList(); elementTagsOk( correctedTags, false ); // Build all tags collection ArrayList allTags = new ArrayList( correctedTags.size() + tags.length ); tags = jdTemp.getTags(); for( int i = 0; i < tags.length; i++ ) { allTags.add( tags[i] ); } allTags.addAll( correctedTags ); /* Iterator it = allTags.iterator(); while( it.hasNext() ) { System.out.println( (JavaDocTag)it.next() ); } */ //getJavaDoc().setRawText( generateRawText( jdTemp.getText(), allTags ) ); jDoc.changeTags( (JavaDocTag[])allTags.toArray( new JavaDocTag[ allTags.size() ] ), JavaDoc.SET ); } ElementFormat getNameFormat () { return nameFormat; } } static class Method extends Constructor { private static final ElementFormat nameFormat = new ElementFormat( "{m} {r} {n} ( {p} )" ); // NOI18N private static final String[] NOT_PERMITTED_TAGS = { TAG_AUTHOR, TAG_SERIAL, TAG_SERIALFIELD, TAG_VERSION }; Method( MethodElement element ) { super( element ); } JavaDoc getJavaDoc() { return ((MethodElement)srcElement).getJavaDoc(); } String typeToString() { return "method"; // NOI18N } String[] getNotPermittedTags() { return NOT_PERMITTED_TAGS; } boolean elementTagsOk() { boolean superOk = super.elementTagsOk(); boolean retOk = checkReturnType( false ); return !superOk ? false : retOk; } private boolean checkReturnType( boolean checkOnly ) { boolean retOk = true; Type ret = ((MethodElement)srcElement).getReturn(); JavaDocTag[] retTags = ((MethodElement)srcElement).getJavaDoc().getTags( TAG_RETURN ); if ( ret == Type.VOID && retTags.length > 0 ) { if ( checkOnly ) { return false; } errorList.addElement( bundle.getString( "ERR_ReturnForVoid" ) ); retOk = false; } else if ( ret != Type.VOID && retTags.length <= 0 ) { if ( checkOnly ) { return false; } errorList.addElement( bundle.getString( "ERR_NoReturn" ) ); retOk = false; } return retOk; } boolean isCorrectable() { if ( super.isCorrectable() ) return true; return !checkReturnType( true ); } void autoCorrect() throws SourceException { JavaDoc jdTemp = JavaDocSupport.createMethodJavaDoc( getJavaDoc().getRawText() ); super.autoCorrect( jdTemp ); if (!checkReturnType( true ) ) { if ( ((MethodElement)srcElement).getReturn() != Type.VOID ) { jdTemp.changeTags( new JavaDocTag[] { JavaDocSupport.createTag( TAG_RETURN, "" ) }, // NOI18N JavaDoc.ADD ); } else { JavaDocTag toRemove[] = jdTemp.getTags( TAG_RETURN ); jdTemp.changeTags( toRemove, JavaDoc.REMOVE ); } } getJavaDoc().setRawText( jdTemp.getRawText() ); } ElementFormat getNameFormat () { return nameFormat; } } } } /* * Log * 14 Gandalf-post-FCS1.12.1.0 4/13/00 Svatopluk Dedic Fixed #6252 * 13 Gandalf 1.12 1/14/00 Petr Hrebejk Exceptions with * fullnames fix mk2 * 12 Gandalf 1.11 1/13/00 Petr Hrebejk AutoComment now * recognizes exception fullnames * 11 Gandalf 1.10 1/12/00 Petr Hrebejk i18n * 10 Gandalf 1.9 1/3/00 Petr Hrebejk Various bugfixes - 4709, * 4978, 5017, 4981, 4976, 5016, 4740, 5005 * 9 Gandalf 1.8 11/9/99 Petr Hrebejk Duplicated innerclasses * in autocomment fixed * 8 Gandalf 1.7 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 7 Gandalf 1.6 9/16/99 Petr Hrebejk Tag descriptions editing * in HTML editor + localization * 6 Gandalf 1.5 8/17/99 Petr Hrebejk @return tag check * 5 Gandalf 1.4 8/16/99 Petr Hrebejk Default Comment changed * to Auto-Correct * 4 Gandalf 1.3 8/13/99 Petr Hrebejk Window serialization * added & Tag change button in Jdoc editor removed * 3 Gandalf 1.2 7/30/99 Petr Hrebejk Autocomment made * TopComponent * 2 Gandalf 1.1 7/26/99 Petr Hrebejk AutoComment tool * implemented * 1 Gandalf 1.0 7/9/99 Petr Hrebejk * $ */